home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Programming / MiniGL / src / texture.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-07  |  24.4 KB  |  1,049 lines

  1. /*
  2.  * $Id: texture.c,v 1.1.1.1 2000/04/07 19:44:51 tfrieden Exp $
  3.  *
  4.  * $Date: 2000/04/07 19:44:51 $
  5.  * $Revision: 1.1.1.1 $
  6.  *
  7.  * (C) 1999 by Hyperion
  8.  * All rights reserved
  9.  *
  10.  * This file is part of the MiniGL library project
  11.  * See the file Licence.txt for more details
  12.  *
  13.  */
  14.  
  15. #include "sysinc.h"
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18.  
  19. static char rcsid[] = "$Id: texture.c,v 1.1.1.1 2000/04/07 19:44:51 tfrieden Exp $";
  20.  
  21.  
  22. #ifndef __PPC__
  23. extern struct ExecBase *SysBase;
  24. #endif
  25.  
  26. void tex_FreeTextures(GLcontext context);
  27. void tex_SetEnv(GLcontext context, GLenum env);
  28. ULONG tex_GLFilter2W3D(GLenum filter);
  29. void tex_SetFilter(GLcontext context, GLenum min, GLenum mag);
  30. void tex_SetWrap(GLcontext context, GLenum wrap_s, GLenum wrap_t);
  31. void RGBA_RGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height);
  32. void RGBA_ARGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height);
  33. void RGB_RGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height);
  34. void RGB_ARGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height);
  35. ULONG MGLConvert(GLcontext context, const GLvoid *inputp, UWORD *output, int width, int height, GLenum internalformat, GLenum format);
  36.  
  37. static ULONG Allocated_Size = 0;
  38. static ULONG Peak_Size      = 0;
  39.  
  40. void *tex_Alloc(ULONG size)
  41. {
  42.     ULONG *x;
  43.     Allocated_Size += size+4;
  44.     x=(ULONG *)malloc(size+4);
  45.     *x = size;
  46.  
  47.     if (Allocated_Size > Peak_Size) Peak_Size = Allocated_Size;
  48.  
  49.     return x+1;
  50. }
  51.  
  52. void tex_Free(void *chunk)
  53. {
  54.     ULONG *mem = (ULONG *)chunk;
  55.     mem--;
  56.     Allocated_Size -= *mem;
  57.     Allocated_Size -= 4;
  58.     free(mem);
  59. }
  60.  
  61. void tex_Statistic(void)
  62. {
  63.     printf("Peak Allocation Size: %ld\n", Peak_Size);
  64. }
  65.  
  66. void MGLTexMemStat(GLcontext context, GLint *Current, GLint *Peak)
  67. {
  68.     if (Current) *Current = (GLint)Allocated_Size;
  69.     if (Peak)    *Peak    = (GLint)Peak_Size;
  70. }
  71.  
  72. void GLDeleteTextures(GLcontext context, GLsizei n, const GLuint *textures)
  73. {
  74.     int i;
  75.     for (i=0; i<n; i++)
  76.     {
  77.         int j = *textures++;
  78.         if (context->w3dTexBuffer[j])
  79.         {
  80.             W3D_FreeTexObj(context->w3dContext, context->w3dTexBuffer[j]);
  81.             context->w3dTexBuffer[j] = NULL;
  82.         }
  83.         if (context->w3dTexMemory[j])
  84.         {
  85.             void *x = context->w3dTexMemory[j];
  86.             tex_Free(x);
  87.             context->w3dTexMemory[j] = NULL;
  88.         }
  89.     }
  90. }
  91.  
  92. void GLGenTextures(GLcontext context, GLsizei n, GLuint *textures)
  93. {
  94.     int i,j;
  95.  
  96.     j = 1;
  97.     for (i=0; i<n; i++)
  98.     {
  99.         while (j < context->TexBufferSize)
  100.         {
  101.             if (context->w3dTexBuffer[j] == NULL) break;
  102.             j++;
  103.         }
  104.         GLFlagError(context, j == context->TexBufferSize, GL_INVALID_OPERATION);
  105.         *textures = j;
  106.         textures++;
  107.     }
  108. }
  109.  
  110.  
  111. void tex_FreeTextures(GLcontext context)
  112. {
  113.     int i;
  114.  
  115.     for (i=0; i<context->TexBufferSize; i++)
  116.     {
  117.         if (context->w3dTexBuffer[i])
  118.         {
  119.             W3D_FreeTexObj(context->w3dContext, context->w3dTexBuffer[i]);
  120.         }
  121.  
  122.         if (context->w3dTexMemory[i])
  123.         {
  124.             tex_Free(context->w3dTexMemory[i]);
  125.         }
  126.  
  127.         context->w3dTexBuffer[i] = 0;
  128.         context->w3dTexMemory[i] = 0;
  129.     }
  130.     W3D_FreeAllTexObj(context->w3dContext);
  131. }
  132.  
  133. void tex_SetEnv(GLcontext context, GLenum env)
  134. {
  135.     W3D_Texture *tex = context->w3dTexBuffer[context->CurrentBinding];
  136.     if (!tex) return;
  137.  
  138.     switch(env)
  139.     {
  140.         case GL_MODULATE:   W3D_SetTexEnv(context->w3dContext, tex, W3D_MODULATE, NULL);
  141.                             break;
  142.         case GL_DECAL:      W3D_SetTexEnv(context->w3dContext, tex, W3D_DECAL, NULL);
  143.                             break;
  144.         case GL_REPLACE:    W3D_SetTexEnv(context->w3dContext, tex, W3D_REPLACE, NULL);
  145.                             break;
  146.         default:            break;
  147.     }
  148. }
  149.  
  150. ULONG tex_GLFilter2W3D(GLenum filter)
  151. {
  152.     switch(filter)
  153.     {
  154.         case GL_NEAREST:                return W3D_NEAREST;
  155.         case GL_LINEAR:                 return W3D_LINEAR;
  156.         case GL_NEAREST_MIPMAP_NEAREST: return W3D_NEAREST_MIP_NEAREST;
  157.         case GL_LINEAR_MIPMAP_NEAREST:  return W3D_LINEAR_MIP_NEAREST;
  158.         case GL_NEAREST_MIPMAP_LINEAR:  return W3D_NEAREST_MIP_LINEAR;
  159.         case GL_LINEAR_MIPMAP_LINEAR:   return W3D_LINEAR_MIP_LINEAR;
  160.     }
  161.     return 0;
  162. }
  163.  
  164. void tex_SetFilter(GLcontext context, GLenum min, GLenum mag)
  165. {
  166.     ULONG minf, magf;
  167.  
  168.     W3D_Texture *tex = context->w3dTexBuffer[context->CurrentBinding];
  169.     if (!tex) return;
  170.  
  171.     minf = tex_GLFilter2W3D(min);
  172.     magf = tex_GLFilter2W3D(mag);
  173.  
  174.     W3D_SetFilter(context->w3dContext, tex, minf, magf);
  175. }
  176.  
  177. void tex_SetWrap(GLcontext context, GLenum wrap_s, GLenum wrap_t)
  178. {
  179.     ULONG Ws,Wt;
  180.     W3D_Texture *tex = context->w3dTexBuffer[context->CurrentBinding];
  181.     if (!tex) return;
  182.  
  183.     if (wrap_s == GL_REPEAT) Ws = W3D_REPEAT;
  184.                         else Ws = W3D_CLAMP;
  185.     if (wrap_t == GL_REPEAT) Wt = W3D_REPEAT;
  186.                         else Wt = W3D_CLAMP;
  187.  
  188.     W3D_SetWrapMode(context->w3dContext, tex, Ws, Wt, NULL);
  189. }
  190.  
  191. void GLTexEnvi(GLcontext context, GLenum target, GLenum pname, GLint param)
  192. {
  193.     //LOG(2, glTexEnvi, "%d %d", pname, param);
  194.     tex_SetEnv(context, param);
  195.     context->TexEnv = (GLenum)param;
  196. }
  197.  
  198. void GLTexParameteri(GLcontext context, GLenum target, GLenum pname, GLint param)
  199. {
  200.     GLenum min, mag;
  201.     GLenum wraps, wrapt;
  202.     //LOG(2, glTexParameteri, "%d %d %d", target, pname, param);
  203.     switch(pname)
  204.     {
  205.         case GL_TEXTURE_MIN_FILTER:
  206.             mag = context->MagFilter;
  207.             tex_SetFilter(context, mag, (GLenum)param);
  208.             context->MinFilter = (GLenum)param;
  209.             break;
  210.         case GL_TEXTURE_MAG_FILTER:
  211.             min = context->MinFilter;
  212.             tex_SetFilter(context, (GLenum)param, min);
  213.             context->MagFilter = (GLenum)param;
  214.             break;
  215.         case GL_TEXTURE_WRAP_S:
  216.             wrapt = context->WrapT;
  217.             tex_SetWrap(context, (GLenum)param, wrapt);
  218.             context->WrapS = (GLenum)param;
  219.             break;
  220.         case GL_TEXTURE_WRAP_T:
  221.             wraps = context->WrapS;
  222.             tex_SetWrap(context, wraps, (GLenum)param);
  223.             context->WrapT = (GLenum)param;
  224.             break;
  225.         default:
  226.             GLFlagError(context, 1, GL_INVALID_ENUM);
  227.     }
  228. }
  229.  
  230. void GLPixelStorei(GLcontext context, GLenum pname, GLint param)
  231. {
  232.     switch(pname)
  233.     {
  234.         case GL_PACK_ALIGNMENT:
  235.             context->PackAlign = param;
  236.             break;
  237.         case GL_UNPACK_ALIGNMENT:
  238.             context->UnpackAlign = param;
  239.             break;
  240.         default:
  241.             // Others here
  242.             break;
  243.     }
  244. }
  245.  
  246. void GLBindTexture(GLcontext context, GLenum target, GLuint texture)
  247. {
  248.     //LOG(2, glBindTexture, "%d %d", target, texture);
  249.     GLFlagError(context, target != GL_TEXTURE_2D, GL_INVALID_ENUM);
  250.     context->CurrentBinding = texture;
  251.     if (context->w3dTexBuffer[context->CurrentBinding] == NULL)
  252.     {   // Set to default for unbound objects
  253.         context->TexEnv    = GL_MODULATE;
  254.         context->MinFilter = GL_NEAREST;
  255.         context->MagFilter = GL_NEAREST;
  256.         context->WrapS     = GL_REPEAT;
  257.         context->WrapT     = GL_REPEAT;
  258.     }
  259. }
  260.  
  261. /*
  262. ** There are two possible output formats:
  263. ** - RGB
  264. ** - RGBA
  265. **
  266. ** There are two possible input formats:
  267. ** - RGB
  268. ** - RGBA
  269. **
  270. ** Thus there must be four conversion routines, since the
  271. ** routine must be able to add or remove the alpha component
  272. **
  273. ** The following set of routines assumes that input is always given as
  274. ** a stream of GL_UNSIGNED_BYTE with either three or four components.
  275. **
  276. ** ROOM FOR IMPROVMENT
  277. ** These routines assume way too much to be considered anything else but
  278. ** special cases. The whole texture stuff should be reworked to include
  279. ** possible convertion routines for all kinds of textures. This could, of
  280. ** course, be left to Warp3D, but this would mean there has to be two sets
  281. ** of textures in memory, which is clearly too much. Perhaps we should
  282. ** change the behaviour of Warp3D in this point - room for discussion.
  283. */
  284.  
  285. #define CORRECT_ALIGN \
  286.         if ((int)input % context->PackAlign) \
  287.         { \
  288.             input += context->PackAlign - ((int)input % context->PackAlign);\
  289.         } \
  290.  
  291. #define ARGBFORM(a,r,g,b) \
  292.     (UWORD)(((( a & 0xf0 ) << 8)  \
  293.     |(( r & 0xf0 ) << 4)  \
  294.     |(( g & 0xf0 )     )  \
  295.     |(( b & 0xf0 ) >> 4)))
  296.  
  297. #define RGBFORM(r,g,b) \
  298.     (UWORD)(0x8000 | ((r & 0xF8) << 7) \
  299.                | ((g & 0xF8) << 2) \
  300.                | ((b & 0xF8) >> 3))
  301.  
  302.  
  303. #define REDBYTE(rgb)    (((UWORD)rgb & 0x7C00) >> 7)
  304. #define GREENBYTE(rgb)  (((UWORD)rgb & 0x03E0) >> 2)
  305. #define BLUEBYTE(rgb)   (((UWORD)rgb & 0x001F) << 3)
  306. #define RGB_GET(i) ((UBYTE *)(context->PaletteData)+3*i)
  307. #define ARGB_GET(i) ((UBYTE *)(context->PaletteData)+4*i)
  308.  
  309. /*
  310. ** This function converts a non-alpha texture buffer into a
  311. ** alpha'ed texture buffer. This is used in case additive blending
  312. ** was selected but the texture does not have alpha, and additive blending
  313. ** is not
  314. */
  315. void tex_AddAlpha(UWORD *output, int width, int height)
  316. {
  317.     int size = width*height;
  318.     int r,g,b,a;
  319.     UWORD x;
  320.  
  321.     while (size)
  322.     {
  323.     x=*output;
  324.     
  325.     r = REDBYTE(x);
  326.     g = GREENBYTE(x);
  327.     b = BLUEBYTE(x);
  328.  
  329.     /*a=(r+g+b)/3;*/
  330.     a=(r>g)?r:g;
  331.     a=(a>b)?a:b;
  332.  
  333.     // These should emulate additive blending, so ensure it's in some appropriate range
  334. /*/        if (a > 240)
  335.     {
  336.         a = 240;
  337.     }*/
  338.  
  339.     a *= 0.8;
  340.  
  341.     *output = ARGBFORM(a,r,g,b);
  342.  
  343.     output++; size--;
  344.     }
  345. }
  346.  
  347.  
  348. /*
  349. ** Convert the currently bound texture to a format that has an alpha channel.
  350. ** Also sets the texture parameters according to the current settings.
  351. */
  352. void tex_ConvertTexture(GLcontext context)
  353. {
  354.     W3D_Texture *newtex;
  355.     W3D_Texture *oldtex = context->w3dTexBuffer[context->CurrentBinding];
  356.     UWORD *output = (UWORD *)context->w3dTexMemory[context->CurrentBinding];
  357.     struct TagItem AllocTags[20];
  358.  
  359.     if (!oldtex) return;
  360.     if (oldtex->texfmtsrc == context->w3dAlphaFormat) return;
  361.  
  362.     tex_AddAlpha(output, oldtex->texwidth, oldtex->texheight);
  363.     AllocTags[0].ti_Tag  = W3D_ATO_IMAGE;
  364.     AllocTags[0].ti_Data = (ULONG)context->w3dTexMemory[context->CurrentBinding];
  365.  
  366.     AllocTags[1].ti_Tag  = W3D_ATO_FORMAT;
  367.     AllocTags[1].ti_Data = context->w3dAlphaFormat;
  368.  
  369.     AllocTags[2].ti_Tag  = W3D_ATO_WIDTH;
  370.     AllocTags[2].ti_Data = oldtex->texwidth;
  371.  
  372.     AllocTags[3].ti_Tag  = W3D_ATO_HEIGHT;
  373.     AllocTags[3].ti_Data = oldtex->texheight;
  374.  
  375.     AllocTags[4].ti_Tag  = TAG_DONE;
  376.     AllocTags[4].ti_Data = 0;
  377.  
  378.     newtex = W3D_AllocTexObj(context->w3dContext, NULL, AllocTags);
  379.     if (!newtex)    return;
  380.     
  381.     W3D_FreeTexObj(context->w3dContext, oldtex);
  382.     context->w3dTexBuffer[context->CurrentBinding] = newtex;
  383.  
  384.     tex_SetEnv(context, context->TexEnv);
  385.     tex_SetFilter(context, context->MinFilter, context->MagFilter);
  386.     tex_SetWrap(context, context->WrapS, context->WrapT);
  387. }
  388.  
  389. void RGBA_RGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height)
  390. {
  391.     int i,j;
  392.     UBYTE r,g,b,a;
  393.     for (i=0; i<height;i++)
  394.     {
  395.         for (j=0; j<width; j++)
  396.         {
  397.             r=*input++;
  398.             g=*input++;
  399.             b=*input++;
  400.             a=*input++;
  401.             *output++ = RGBFORM(r,g,b);
  402.             CORRECT_ALIGN
  403.         }
  404.     }
  405. }
  406.  
  407. void RGBA_ARGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height)
  408. {
  409.     int i,j;
  410.     UBYTE r,g,b,a;
  411.     for (i=0; i<height;i++)
  412.     {
  413.         for (j=0; j<width; j++)
  414.         {
  415.             r=*input++;
  416.             g=*input++;
  417.             b=*input++;
  418.             a=*input++;
  419.             *output++ = ARGBFORM(a,r,g,b);
  420.             CORRECT_ALIGN
  421.         }
  422.     }
  423. }
  424.  
  425. void RGB_RGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height)
  426. {
  427.     int i,j;
  428.     UBYTE r,g,b;
  429.     for (i=0; i<height;i++)
  430.     {
  431.         for (j=0; j<width; j++)
  432.         {
  433.             r=*input++;
  434.             g=*input++;
  435.             b=*input++;
  436.             *output++ = RGBFORM(r,g,b);
  437.             CORRECT_ALIGN
  438.         }
  439.     }
  440. }
  441.  
  442. void RGB_ARGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height)
  443. {
  444.     int i,j;
  445.     UBYTE r,g,b;
  446.     for (i=0; i<height;i++)
  447.     {
  448.         for (j=0; j<width; j++)
  449.         {
  450.             r=*input++;
  451.             g=*input++;
  452.             b=*input++;
  453.             *output++ = ARGBFORM(255,r,g,b);
  454.             CORRECT_ALIGN
  455.         }
  456.     }
  457. }
  458.  
  459. void INDEX_RGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height)
  460. {
  461.     int i,j;
  462.     UBYTE ind;
  463.     UBYTE r,g,b;
  464.  
  465.     if (context->PaletteFormat == GL_RGB)
  466.     {
  467.         for (i=0; i<height; i++)
  468.         {
  469.             for (j=0; j<width; j++)
  470.             {
  471.                 ind = *input++;
  472.                 r = *RGB_GET(ind);
  473.                 g = *(RGB_GET(ind)+1);
  474.                 b = *(RGB_GET(ind)+2);
  475.                 *output++ = RGBFORM(r,g,b);
  476.                 CORRECT_ALIGN
  477.             }
  478.         }
  479.     }
  480.     else
  481.     {
  482.         for (i=0; i<height; i++)
  483.         {
  484.             for (j=0; j<width; j++)
  485.             {
  486.                 ind = *input++;
  487.                 r = *RGB_GET(ind);
  488.                 g = *(ARGB_GET(ind)+1);
  489.                 b = *(ARGB_GET(ind)+2);
  490.                 *output++ = RGBFORM(r,g,b);
  491.                 CORRECT_ALIGN
  492.             }
  493.         }
  494.  
  495.     }
  496. }
  497.  
  498. void INDEX_ARGB(GLcontext context, GLubyte *input, UWORD *output, int width, int height)
  499. {
  500.     int i,j;
  501.     UBYTE ind;
  502.     UBYTE r,g,b,a;
  503.  
  504.     if (context->PaletteFormat == GL_RGB)
  505.     {
  506.         for (i=0; i<height; i++)
  507.         {
  508.             for (j=0; j<width; j++)
  509.             {
  510.                 ind = *input++;
  511.                 r = *RGB_GET(ind);
  512.                 g = *(RGB_GET(ind)+1);
  513.                 b = *(RGB_GET(ind)+2);
  514.                 *output++ = ARGBFORM(255,r,g,b);
  515.                 CORRECT_ALIGN
  516.             }
  517.         }
  518.     }
  519.     else
  520.     {
  521.         for (i=0; i<height; i++)
  522.         {
  523.             for (j=0; j<width; j++)
  524.             {
  525.                 ind = *input++;
  526.                 r = *RGB_GET(ind);
  527.                 g = *(ARGB_GET(ind)+1);
  528.                 b = *(ARGB_GET(ind)+2);
  529.                 a = *(ARGB_GET(ind)+3);
  530.                 *output++ = ARGBFORM(a,r,g,b);
  531.                 CORRECT_ALIGN
  532.             }
  533.         }
  534.  
  535.     }
  536. }
  537.  
  538. void L8_L8(GLcontext context, GLubyte *input, GLubyte *output, int width, int height)
  539. {
  540.     int i,j;
  541.  
  542.     for (i=0; i<height;i++)
  543.     {
  544.         for (j=0; j<width; j++) {
  545.             *output++ = *input++;
  546.         }
  547.     }
  548. }
  549.  
  550. ULONG MGLConvert(GLcontext context, const GLvoid *inputp, UWORD *output, int width, int height, GLenum internalformat, GLenum format)
  551. {
  552.     GLvoid *input = (GLvoid *)inputp;
  553.  
  554.     switch(internalformat) // The format the texture should have
  555.     {
  556.         case GL_LUMINANCE:
  557.             switch(format) // the format of the pixel (input) data
  558.             {
  559.                 case GL_LUMINANCE:
  560.                     L8_L8(context, (GLubyte *)input, (GLubyte *)output, width, height);
  561.                     return W3D_L8;
  562.             }
  563.             break;
  564.  
  565.         case 3:
  566.         case GL_RGB:
  567.             switch(format) // the format of the pixel (input) data
  568.             {
  569.                 case GL_RGB:
  570.                     RGB_RGB(context, (GLubyte *)input, output, width, height);
  571.                     return context->w3dFormat;
  572.                 case GL_RGBA:
  573.                     RGBA_RGB(context, (GLubyte *)input, output, width, height);
  574.                     return context->w3dFormat;
  575.                 case GL_COLOR_INDEX:
  576.                     INDEX_RGB(context, (GLubyte *)input, output, width, height);
  577.                     return context->w3dFormat;
  578.             }
  579.             break;
  580.  
  581.         case 4:
  582.         case GL_RGBA:
  583.             switch(format) // format of the pixel (input) data
  584.             {
  585.                 case GL_RGB:
  586.                     RGB_ARGB(context, (GLubyte *)input, output, width, height);
  587.                     return context->w3dAlphaFormat;
  588.                 case GL_RGBA:
  589.                     RGBA_ARGB(context, (GLubyte *)input, output, width, height);
  590.                     return context->w3dAlphaFormat;
  591.                 case GL_COLOR_INDEX:
  592.                     INDEX_ARGB(context, (GLubyte *)input, output, width, height);
  593.                     return context->w3dAlphaFormat;
  594.             }
  595.             break;
  596.     }
  597. }
  598.  
  599. void GLTexImage2DNoMIP(GLcontext context, GLenum gltarget, GLint level,
  600.     GLint internalformat, GLsizei width, GLsizei height, GLint border,
  601.     GLenum format, GLenum type, const GLvoid *pixels);
  602.  
  603.  
  604. void GLTexImage2D(GLcontext context, GLenum gltarget, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
  605. {
  606.     int current = context->CurrentBinding;
  607.     ULONG w,h;
  608.     ULONG targetsize;
  609.     ULONG error;
  610.     UBYTE *target;
  611.     int i,iw,ih;
  612.     void *miparray[16];
  613.     ULONG useFormat;
  614.  
  615.     struct TagItem AllocTags[20];
  616.  
  617.     if (context->NoMipMapping == GL_TRUE)
  618.     {
  619.         GLTexImage2DNoMIP(context, gltarget, level, internalformat, width,
  620.             height, border, format, type, pixels);
  621.         return;
  622.     }
  623.  
  624.     //LOG(3, glTexImage2D, "target = %d level=%d, size=%d×%d", gltarget, level, width, height);
  625.     GLFlagError(context, type != GL_UNSIGNED_BYTE, GL_INVALID_OPERATION);
  626.     GLFlagError(context, gltarget != GL_TEXTURE_2D, GL_INVALID_ENUM);
  627.  
  628.     /*
  629.     ** We will use width and height only when the mipmap level
  630.     ** is really 0. Otherwise, we need to upscale the values
  631.     ** according to the level.
  632.     **
  633.     ** Note this will most likely be difficult with non-square
  634.     ** textures, as the first side to reach one will remain
  635.     ** there. For example, consider the sequence
  636.     ** 8x4, 4x2, 2x1, 1x1
  637.     **  0     1   2    3
  638.     ** If the 1x1 mipmap is given, upscaling will yield 8x8, not 8x4
  639.     */
  640.  
  641.     w=(ULONG)width;
  642.     h=(ULONG)height;
  643.     if (level)
  644.     {
  645.         int i=level;
  646.         while (i)
  647.         {
  648.             w*=2; h*=2; i--;
  649.         }
  650.     }
  651.  
  652.     if (context->w3dTexBuffer[current] == NULL)
  653.     {
  654.         /*
  655.         ** Create a new texture object
  656.         ** Get the memory
  657.         */
  658.  
  659.         targetsize = (w * h * context->w3dBytesPerTexel * 4) / 3;
  660.         if (context->w3dTexMemory[current])
  661.             tex_Free(context->w3dTexMemory[current]);
  662.         context->w3dTexMemory[current] = (GLubyte *)tex_Alloc(targetsize);
  663.         if (!context->w3dTexMemory[current])
  664.             return;
  665.     }
  666.  
  667.     /*
  668.     ** Find the starting address for the given mipmap level in the
  669.     ** texture memory area
  670.     */
  671.  
  672.     target = context->w3dTexMemory[current];
  673.     i = level;
  674.     iw = w; ih=h;
  675.     while (i)
  676.     {
  677.         target += iw * ih * context->w3dBytesPerTexel;
  678.         i      -- ;
  679.         if (iw>1) iw/=2;
  680.         if (ih>1) ih/=2;
  681.     }
  682.  
  683.     /*
  684.     ** Convert the data to the target address
  685.     */
  686.     useFormat = MGLConvert(context, pixels, (UWORD *)target, width, height, internalformat, format);
  687.  
  688.     /*
  689.     ** Create a new W3D_Texture if none was present, using the converted
  690.     ** data.
  691.     ** Otherwise, call W3D_UpdateTexImage
  692.     */
  693.  
  694.     if (context->w3dTexBuffer[current] == NULL)
  695.     {
  696.         i=0;
  697.         iw=w;
  698.         ih=h;
  699.         target = context->w3dTexMemory[current];
  700.         while (1)
  701.         {
  702.             miparray[i++] = target;
  703.             if (iw == 1 && ih == 1) break;
  704.  
  705.             target += iw * ih * context->w3dBytesPerTexel;
  706.             if (iw > 1)     iw     /= 2;
  707.             if (ih > 1)     ih     /= 2;
  708.         }
  709.  
  710.         AllocTags[0].ti_Tag  = W3D_ATO_IMAGE;
  711.         AllocTags[0].ti_Data = (ULONG)context->w3dTexMemory[current];
  712.  
  713.         AllocTags[1].ti_Tag  = W3D_ATO_FORMAT;
  714.         AllocTags[1].ti_Data = useFormat;
  715.  
  716.         AllocTags[2].ti_Tag  = W3D_ATO_WIDTH;
  717.         AllocTags[2].ti_Data = w;
  718.  
  719.         AllocTags[3].ti_Tag  = W3D_ATO_HEIGHT;
  720.         AllocTags[3].ti_Data = h;
  721.  
  722.         AllocTags[4].ti_Tag  = W3D_ATO_MIPMAP;
  723.         AllocTags[4].ti_Data = 0;
  724.  
  725.         AllocTags[5].ti_Tag  = W3D_ATO_MIPMAPPTRS;
  726.         AllocTags[5].ti_Data = (ULONG)miparray;
  727.  
  728.         AllocTags[6].ti_Tag  = TAG_DONE;
  729.         AllocTags[6].ti_Data = 0;
  730.  
  731.         context->w3dTexBuffer[current] = W3D_AllocTexObj(context->w3dContext, &error, AllocTags);
  732.  
  733.         if (context->w3dTexBuffer[current] == NULL || error != W3D_SUCCESS) return;
  734.  
  735.         /*
  736.         ** Set the appropriate wrap modes, texture env, and filters
  737.         */
  738.         tex_SetWrap(context, context->WrapS, context->WrapT);
  739.         tex_SetFilter(context, context->MinFilter, context->MagFilter);
  740.         tex_SetEnv(context, context->TexEnv);
  741.  
  742.     }
  743.     else
  744.     {
  745.         W3D_UpdateTexImage(context->w3dContext, context->w3dTexBuffer[current],
  746.             target, level, NULL);
  747.     }
  748. }
  749.  
  750. void GLTexImage2DNoMIP(GLcontext context, GLenum gltarget, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
  751. {
  752.     int current = context->CurrentBinding;
  753.     ULONG w,h;
  754.     ULONG targetsize;
  755.     ULONG error;
  756.     UBYTE *target;
  757.     ULONG useFormat;
  758.     static struct TagItem AllocTags[20];
  759.  
  760.     //LOG(3, glTexImage2DNoMIP, "target = %d level=%d, size=%d×%d", gltarget, level, width, height);
  761.     GLFlagError(context, type != GL_UNSIGNED_BYTE, GL_INVALID_OPERATION);
  762.     GLFlagError(context, gltarget != GL_TEXTURE_2D, GL_INVALID_ENUM);
  763.  
  764.     if (level != 0) return;
  765.  
  766.     w=(ULONG)width;
  767.     h=(ULONG)height;
  768.  
  769.     if (context->w3dTexBuffer[current] == NULL)
  770.     {
  771.     /*
  772.     ** Create a new texture object
  773.     ** Get the memory
  774.     */
  775.  
  776.     targetsize = (w * h * context->w3dBytesPerTexel);
  777.     if (context->w3dTexMemory[current])
  778.         tex_Free(context->w3dTexMemory[current]);
  779.     context->w3dTexMemory[current] = (GLubyte *)tex_Alloc(targetsize);
  780.     if (!context->w3dTexMemory[current])
  781.         return;
  782.     }
  783.  
  784.     target = context->w3dTexMemory[current];
  785.  
  786.     /*
  787.     ** Convert the data to the target address
  788.     */
  789.     useFormat = MGLConvert(context, pixels, (UWORD *)target, width, height, internalformat, format);
  790.  
  791.     /*
  792.     ** Create a new W3D_Texture if none was present, using the converted
  793.     ** data.
  794.     ** Otherwise, call W3D_UpdateTexImage
  795.     */
  796.  
  797.     if (context->w3dTexBuffer[current] == NULL)
  798.     {
  799.     W3D_Texture *tex;
  800.  
  801.     AllocTags[0].ti_Tag  = W3D_ATO_IMAGE;
  802.     AllocTags[0].ti_Data = (ULONG)context->w3dTexMemory[current];
  803.  
  804.     AllocTags[1].ti_Tag  = W3D_ATO_FORMAT;
  805.     AllocTags[1].ti_Data = useFormat;
  806.  
  807.     AllocTags[2].ti_Tag  = W3D_ATO_WIDTH;
  808.     AllocTags[2].ti_Data = w;
  809.  
  810.     AllocTags[3].ti_Tag  = W3D_ATO_HEIGHT;
  811.     AllocTags[3].ti_Data = h;
  812.  
  813.     AllocTags[4].ti_Tag  = TAG_DONE;
  814.     AllocTags[4].ti_Data = 0;
  815.  
  816.     tex = W3D_AllocTexObj(context->w3dContext, &error, AllocTags);
  817.  
  818.     if (tex == NULL || error != W3D_SUCCESS) return;
  819.  
  820.     context->w3dTexBuffer[current] = tex;
  821.  
  822.     /*
  823.     ** Set the appropriate wrap modes, texture env, and filters
  824.     */
  825.     tex_SetWrap(context, context->WrapS, context->WrapT);
  826.     tex_SetFilter(context, context->MinFilter, context->MagFilter);
  827.     tex_SetEnv(context, context->TexEnv);
  828.  
  829.     }
  830.     else
  831.     {
  832.     W3D_UpdateTexImage(context->w3dContext, context->w3dTexBuffer[current],
  833.         context->w3dTexMemory[current], 0, NULL);
  834.     }
  835. }
  836.  
  837. inline void tex_UpdateScanlineAlpha(UWORD *start, UBYTE *pixels, int numpixels)
  838. {
  839.     int i;
  840.     UBYTE r,g,b,a;
  841.     for (i=0; i<numpixels; i++)
  842.     {
  843.         r=*pixels++;
  844.         g=*pixels++;
  845.         b=*pixels++;
  846.         a=*pixels++;
  847.  
  848.         *start = ARGBFORM(a,r,g,b);
  849.         start++;
  850.     }
  851. }
  852.  
  853. inline void tex_UpdateScanlineNoAlpha(UWORD *start, UBYTE *pixels, int numpixels)
  854. {
  855.     int i;
  856.     UBYTE r,g,b,a;
  857.     for (i=0; i<numpixels; i++)
  858.     {
  859.         r=*pixels++;
  860.         g=*pixels++;
  861.         b=*pixels++;
  862.         a=*pixels++;
  863.  
  864.         *start = RGBFORM(r,g,b);
  865.         start++;
  866.     }
  867. }
  868.  
  869. inline void tex_UpdateScanlineVerbatim(UBYTE *start, UBYTE *pixels, int numpixels)
  870. {
  871.     memcpy(pixels, start, numpixels);
  872. }
  873.  
  874. void GLTexSubImage2DNoMIP(GLcontext context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
  875.  
  876. void GLTexSubImage2D(GLcontext context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
  877. {
  878.     int current = context->CurrentBinding;
  879.  
  880.     if (context->NoMipMapping == GL_TRUE)
  881.     {
  882.         GLTexSubImage2DNoMIP(context, target, level, xoffset, yoffset, width, height, format, type, (void *)pixels);
  883.         return;
  884.     }
  885.  
  886.     GLFlagError(context, target!=GL_TEXTURE_2D, GL_INVALID_ENUM);
  887.     GLFlagError(context, context->w3dTexBuffer[current] == NULL, GL_INVALID_OPERATION);
  888.  
  889. //    GLFlagError(context, 1, GL_INVALID_OPERATION);
  890. }
  891.  
  892. void GLTexSubImage2DNoMIP(GLcontext context, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
  893. {
  894.     UBYTE *where;
  895.     UBYTE *from = pixels;
  896.     int current = context->CurrentBinding;
  897.     int linelength;
  898.     int sourcelength, sourceunit;
  899.     int i;
  900.  
  901.  
  902.     GLFlagError(context, target!=GL_TEXTURE_2D, GL_INVALID_ENUM);
  903.     GLFlagError(context, context->w3dTexBuffer[context->CurrentBinding] == NULL, GL_INVALID_OPERATION);
  904.     GLFlagError(context, type != GL_UNSIGNED_BYTE, GL_INVALID_ENUM);
  905.  
  906.     switch(format)
  907.     {
  908.         case GL_LUMINANCE:
  909.             sourceunit = 1;
  910.             break;
  911.  
  912.         case GL_RGBA:
  913.         case 4:
  914.             sourceunit = 4;
  915.             break;
  916.  
  917.         case GL_RGB:
  918.         case 3:
  919.             sourceunit = 3;
  920.             break;
  921.     }
  922.  
  923.     linelength = context->w3dTexBuffer[current]->texwidth * context->w3dBytesPerTexel;
  924.  
  925.     sourcelength = width * sourceunit;
  926.  
  927.     where = (UBYTE *)context->w3dTexMemory[current]
  928.       +          linelength * yoffset
  929.       +          context->w3dBytesPerTexel * xoffset;
  930.  
  931.     if (context->w3dTexBuffer[current]->texfmtsrc == context->w3dFormat)
  932.     {
  933.         for (i=0; i<height; i++)
  934.         {
  935.             tex_UpdateScanlineNoAlpha((UWORD *)where, from, width);
  936.             where += linelength;
  937.             from  += sourcelength;
  938.         }
  939.     }
  940.     else if (context->w3dTexBuffer[current]->texfmtsrc == context->w3dAlphaFormat)
  941.     {
  942.         for (i=0; i<height; i++)
  943.         {
  944.             tex_UpdateScanlineAlpha((UWORD *)where, from, width);
  945.             where += linelength;
  946.             from  += sourcelength;
  947.         }
  948.     }
  949.     else
  950.     {
  951.         for (i=0; i<height; i++)
  952.         {
  953.             tex_UpdateScanlineVerbatim((UBYTE *)where, from, width*sourceunit);
  954.             where += linelength;
  955.             from  += sourcelength;
  956.         }
  957.     }
  958.  
  959.     W3D_UpdateTexImage(context->w3dContext, context->w3dTexBuffer[current],
  960.     context->w3dTexMemory[current], 0, NULL);
  961. }
  962.  
  963. void GLTexGeni(GLcontext context, GLenum coord, GLenum mode, GLenum map)
  964. {
  965. //    GLFlagError(context, 1, GL_INVALID_OPERATION);
  966. }
  967.  
  968. void GLColorTable(GLcontext context, GLenum target, GLenum internalformat, GLint width, GLenum format, GLenum type, GLvoid *data)
  969. {
  970.     int i;
  971.     GLubyte *palette;
  972.     GLubyte *where;
  973.     GLubyte a,r,g,b;
  974.  
  975.     GLFlagError(context, width>256, GL_INVALID_VALUE);
  976.     GLFlagError(context, target!=GL_COLOR_TABLE, GL_INVALID_OPERATION);
  977.  
  978.     palette = (GLubyte *)data;
  979.     where   = (GLubyte *)context->PaletteData;
  980.  
  981.     GLFlagError(context, where == NULL, GL_INVALID_OPERATION);
  982.  
  983.     switch(internalformat)
  984.     {
  985.         case 4:
  986.         case GL_RGBA: // convert to argb from...
  987.             switch(format)
  988.             {
  989.                 case GL_RGB: // ...RGB, ignoring alpha
  990.                     for (i=0; i<width; i++)
  991.                     {
  992.                         r=*palette++;
  993.                         g=*palette++;
  994.                         b=*palette++;
  995.                         palette++;
  996.                         *where++ = r;
  997.                         *where++ = g;
  998.                         *where++ = b;
  999.                     }
  1000.                     break;
  1001.                 case GL_RGBA: // ...ARGB with alpha
  1002.                     for (i=0; i<width; i++)
  1003.                     {
  1004.                         a=*palette++;
  1005.                         r=*palette++;
  1006.                         g=*palette++;
  1007.                         b=*palette++;
  1008.                         *where++ = a;
  1009.                         *where++ = r;
  1010.                         *where++ = g;
  1011.                         *where++ = b;
  1012.                     }
  1013.                     break;
  1014.             }
  1015.             break;
  1016.         case 3:
  1017.         case GL_RGB: // convert to RGB from...
  1018.             switch(format)
  1019.             {
  1020.                 case GL_RGB: // ...RGB without alpha
  1021.                     for (i=0; i<width; i++)
  1022.                     {
  1023.                         r=*palette++;
  1024.                         g=*palette++;
  1025.                         b=*palette++;
  1026.                         *where++ = r;
  1027.                         *where++ = g;
  1028.                         *where++ = b;
  1029.                     }
  1030.                     break;
  1031.                 case GL_RGBA: // ...ARGB, assuming alpha == 1
  1032.                     for (i=0; i<width; i++)
  1033.                     {
  1034.                         r=*palette++;
  1035.                         g=*palette++;
  1036.                         b=*palette++;
  1037.                         *where++ = 255;
  1038.                         *where++ = r;
  1039.                         *where++ = g;
  1040.                         *where++ = b;
  1041.                     }
  1042.                     break;
  1043.             }
  1044.             break;
  1045.     }
  1046.     context->PaletteFormat = format;
  1047.     context->PaletteSize   = width;
  1048. }
  1049.